﻿using bilibili下载.Interface;
using Downloader;
using HttpHelper;
using Newtonsoft.Json;
using NLog;
using Prism.Mvvm;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Threading;
using System.Windows.Media.Imaging;

namespace bilibili下载.Models
{
    public class AVInfo : BindableBase, IAVInfo
    {
        private static readonly Logger logger = LogManager.GetCurrentClassLogger();

        public string Name { get; set; }

        private bool _checked;

        public bool Checked
        {
            get { return _checked; }
            set { SetProperty(ref _checked, value); }
        }

        private double percentage;

        public double Percentage
        {
            get { return percentage; }
            set { SetProperty(ref percentage, value); }
        }

        private State state;

        public State State
        {
            get { return state; }
            set { SetProperty(ref state, value); }
        }

        public BitmapImage Image { get; set; }
        public int Id { get; set; }

        public AVInfo(string aId, string cId)
        {
            AId = aId; CId = cId;
        }

        private string AId { get; }
        private string CId { get; }

        private long totalLen;

        public long TotalLen
        {
            get { return totalLen; }
            set { SetProperty(ref totalLen, value); }
        }

        private long receivedSize;

        public long ReceivedSize
        {
            get { return receivedSize; }
            set { SetProperty(ref receivedSize, value); }
        }

        private double secondSpeed;

        public double SecondSpeed
        {
            get { return secondSpeed; }
            set { SetProperty(ref secondSpeed, value); }
        }

        private double averageSecondSpeed;

        public double AverageSecondSpeed
        {
            get { return averageSecondSpeed; }
            set { SetProperty(ref averageSecondSpeed, value); }
        }

        private static DownloadConfiguration Options;

        static AVInfo()
        {
            Options = new DownloadConfiguration()
            {
                //BufferBlockSize = 10240, // 通常，主机支持最大到 8000 字节，默认值为 8000
                ChunkCount = 3, // 要下载的文件分块，默认值为 1
                //MaximumBytesPerSecond = 1024 * 1024, // 下载速度限制为1MB/s，默认值为零或无限
                MaxTryAgainOnFailover = int.MaxValue, // 最大失败次数
                OnTheFlyDownload = false, //是否在内存中缓存? 默认值为true
                ParallelDownload = true, // 下载部分文件是否并行。 默认值为false
                TempDirectory = @".\视频缓存",//tempDirectory, // 设置缓冲块文件的临时路径，默认路径为 Path.GetTempPath()
                Timeout = 1000, // 每个流块读取器的超时时间(毫秒)，默认值为1000
                RequestConfiguration = // 配置和自定义请求头
                {
                    Accept = "*/*",
                    AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate,
                    //CookieContainer =  new CookieContainer(), // Add your cookies
                    //Headers = new WebHeaderCollection(), // Add your custom headers
                    KeepAlive = false,
                    Referer ="https://www.bilibili.com",
                    ProtocolVersion = HttpVersion.Version11, // Default value is HTTP 1.1
                    UseDefaultCredentials = false,
                    UserAgent = HeaderValue.UserAgent
                }
            };
        }

        public void Download(string path)
        {
            try
            {
                if (GetUrl(out var url))
                {
                    path = Path.Combine(path, $"{Id:00}-{Name}.flv");
                    logger.Debug("AId：{0},CId：{1},开始下载", AId, CId);
                    Download(path, url);
                    //WebClientDownload(path, url);
                    logger.Debug("AId：{0},CId：{1},下载完成", AId, CId);
                }
            }
            catch (Exception e)
            {
                logger.Error(e, "AId：{0},CId：{1},下载失败", AId, CId);
            }
        }

        private void Download(string path, string url)
        {
            using (var downloader = new DownloadService(Options))
            {
                // 开始下载 提供文件路径和文件大小
                downloader.DownloadStarted += (a, b) =>
                {
                    TotalLen = b.TotalBytesToReceive;
                    State = State.Underway;
                };
                //提供有关下载进度的任何信息，如进度块的总和百分比，总速度，平均速度，总接收字节和接收字节数组的直播流。
                downloader.DownloadProgressChanged += (a, b) =>
                {
                    Percentage = b.ProgressPercentage;
                    ReceivedSize = b.ReceivedBytesSize;
                    SecondSpeed = b.BytesPerSecondSpeed / 1024;
                    AverageSecondSpeed = b.AverageBytesPerSecondSpeed / 1024;
                };
                // 下载完成事件，可以包括发生错误、取消或成功下载完成。
                downloader.DownloadFileCompleted += (a, b) =>
                {
                    if (b.Error != null)
                    {
                        logger.Error(b.Error, "AId：{0},CId：{1},下载失败", AId, CId);
                    }
                    else State = State.Finish;
                };
                int tautology = 0;
                while (State != State.Finish && tautology++ <= 3)
                {
                    try
                    {
                        downloader.DownloadFileTaskAsync(url, path).Wait();
                    }
                    catch (Exception e)
                    {
                        logger.Error(e, "AId：{0},CId：{1},下载失败", AId, CId);
                        Thread.Sleep(1000 * 10);
                    }
                }
            }
        }

        private bool GetUrl(out string url)
        {
            WinHttp http = new WinHttp();
            var query = new Dictionary<string, string>
            {
                ["fnval"] = "0",
                ["avid"] = AId,
                ["aid"] = AId,
                ["cid"] = CId,
                ["fourk"] = "1",
                ["qn"] = "116",
                ["access_key"] = "",
            };
            logger.Debug("AId：{0},CId：{1},获取下载地址", AId, CId);
            http.Open(Method.GET, "https://api.bilibili.com/x/player/playurl", query);
            var data = http.Send();
            if (data.IsSuccessStatus)
            {
                logger.Debug("AId：{0},CId：{1},内容：{2}", AId, CId, data.Text);
                var result = JsonConvert.DeserializeObject<AvResponse>(data.Text);
                if (result.code == 0)
                {
                    if (result?.data?.durl?.Length > 0)
                    {
                        url = result.data.durl.First().url;
                        return true;
                    }
                    else logger.Debug("AId：{0},CId：{1},下载地址长度为 \"0\"", AId, CId);
                }
                else logger.Debug("AId：{0},CId：{1},解析错误", AId, CId);
            }
            else logger.Debug("AId：{0},CId：{1},获取失败.状态码：{2}.状态信息：{3}.错误描述：{4}", AId, CId, data.StatusCode, data.Status, data.Message);
            url = string.Empty;
            return false;
        }

        //{"code":0,"message":"0","ttl":1,"data":{"from":"local","result":"suee","message":"","quality":64,"format":"flv720","timelength":43443,"accept_format":"flv,flv720,flv480,mp4","accept_description":["高清 1080P","高清 720P","清晰 480P","流畅 360P"],"accept_quality":[80,64,32,16],"video_codecid":7,"seek_param":"start","seek_type":"offset","durl":[{"order":1,"length":43443,"size":1501609,"ahead":"","vhead":"","url":"https://upos-sz-mirrorcos.bilivideo.com/upgcxcode/84/25/272132584/272132584_nb2-1-64.flv?e=ig8euxZM2rNcNb4BhwdVtW4BhwdVNEVEuCIv29hEn0lqXg8Y2ENvNCImNEVEUJ1miI7MT96fqj3E9r1qNCNEtodEuxTEtodE9EKE9IMvXBvE2ENvNCImNEVEK9GVqJIwqa80WXIekXRE9IMvXBvEuENvNCImNEVEua6m2jIxux0CkF6s2JZv5x0DQJZY2F8SkXKE9IB5QK==\u0026uipk=5\u0026nbs=1\u0026deadline=1626795164\u0026gen=playurlv2\u0026os=cosbv\u0026oi=719644639\u0026trid=5f278d69f2c942a08ccf5323c169d8d0u\u0026platform=pc\u0026upsig=52ab0a7c43c2e281733e208cbd2a69d3\u0026uparams=e,uipk,nbs,deadline,gen,os,oi,trid,platform\u0026mid=0\u0026bvc=vod\u0026nettype=0\u0026orderid=0,3\u0026agrr=0\u0026logo=80000000","backup_url":["https://upos-sz-mirrorcos.bilivideo.com/upgcxcode/84/25/272132584/272132584_nb2-1-64.flv?e=ig8euxZM2rNcNb4BhwdVtW4BhwdVNEVEuCIv29hEn0lqXg8Y2ENvNCImNEVEUJ1miI7MT96fqj3E9r1qNCNEtodEuxTEtodE9EKE9IMvXBvE2ENvNCImNEVEK9GVqJIwqa80WXIekXRE9IMvXBvEuENvNCImNEVEua6m2jIxux0CkF6s2JZv5x0DQJZY2F8SkXKE9IB5QK==\u0026uipk=5\u0026nbs=1\u0026deadline=1626795164\u0026gen=playurlv2\u0026os=cosbv\u0026oi=719644639\u0026trid=5f278d69f2c942a08ccf5323c169d8d0u\u0026platform=pc\u0026upsig=52ab0a7c43c2e281733e208cbd2a69d3\u0026uparams=e,uipk,nbs,deadline,gen,os,oi,trid,platform\u0026mid=0\u0026bvc=vod\u0026nettype=0\u0026orderid=1,3\u0026agrr=0\u0026logo=40000000","https://upos-sz-mirrorcosb.bilivideo.com/upgcxcode/84/25/272132584/272132584_nb2-1-64.flv?e=ig8euxZM2rNcNb4BhwdVtW4BhwdVNEVEuCIv29hEn0lqXg8Y2ENvNCImNEVEUJ1miI7MT96fqj3E9r1qNCNEtodEuxTEtodE9EKE9IMvXBvE2ENvNCImNEVEK9GVqJIwqa80WXIekXRE9IMvXBvEuENvNCImNEVEua6m2jIxux0CkF6s2JZv5x0DQJZY2F8SkXKE9IB5QK==\u0026uipk=5\u0026nbs=1\u0026deadline=1626795164\u0026gen=playurlv2\u0026os=cosbbv\u0026oi=719644639\u0026trid=5f278d69f2c942a08ccf5323c169d8d0u\u0026platform=pc\u0026upsig=ec9eb1df74aabee79685154547e61d48\u0026uparams=e,uipk,nbs,deadline,gen,os,oi,trid,platform\u0026mid=0\u0026bvc=vod\u0026nettype=0\u0026orderid=2,3\u0026agrr=0\u0026logo=40000000"]}],"support_formats":[{"quality":80,"format":"flv","new_description":"1080P 高清","display_desc":"1080P","superscript":""},{"quality":64,"format":"flv720","new_description":"720P 高清","display_desc":"720P","superscript":""},{"quality":32,"format":"flv480","new_description":"480P 清晰","display_desc":"480P","superscript":""},{"quality":16,"format":"mp4","new_description":"360P 流畅","display_desc":"360P","superscript":""}],"high_format":null}}

        private class AvResponse
        {
            public int code { get; set; }
            public string message { get; set; }

            public AvData data { get; set; }
        }

        private class AvData
        {
            public int video_codecid { get; set; }

            public Durl[] durl { get; set; }
        }

        private class Durl
        {
            public string url { get; set; }
        }
    }
}